﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Xml;
using System.Xml.Xsl;
using System.Diagnostics;
using System.Threading;

namespace GUI
{
    class TradingClient
    {

        List<string> bids = new List<string>();
        List<string> offers = new List<string>();
        List<string> position = new List<string>();

        Socket mdcSocket;
        byte[] receiveBuffer;
        byte[] sendBuffer;

        //string[] currentTickers = { "TRAN", "LEGL", "WELL", "ADMN", "HEAL", "UTIL", "SECR", "FIRE" };
        IPAddress groupAddress;
        MulticastOption mcastOption;
        EndPoint localEP;
        EndPoint endPoint;
        IPHostEntry entry;
        //BizDomain domain;
        string tradingID;
        string order;
        string serv;
        bool login;


        public TradingClient(string trader)
        {
            login = false;
            tradingID = trader;
            //domain = BizDomain;
            receiveBuffer = new byte[1000000];
            sendBuffer = new byte[512];
            groupAddress = IPAddress.Parse("224.5.6.7");
            mcastOption = new MulticastOption(groupAddress);
            //currentTickers = domain.oprocNames;

        }


        private void TraderLogin()
        {
            Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint mdpEP = new IPEndPoint(IPAddress.Loopback, 20000);
            sendBuffer = Encoding.ASCII.GetBytes(tradingID);
            mSocket.Connect(mdpEP);
            mSocket.Send(sendBuffer);
            mSocket.Close();
            createXSLT();
        }

        private void SendOrder()
        {
            Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint mdpEP = new IPEndPoint(IPAddress.Loopback, 20000);
            mSocket.Connect(mdpEP);
            mSocket.Send(sendBuffer);
            mSocket.Close();
            //Console.WriteLine("Sending Order " + order);
            //Console.WriteLine("Order Input Success!");
            getQuotes(serv);
        }

        private void getQuotes(string service)
        {
            Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint mdpEP = new IPEndPoint(IPAddress.Loopback, 20000);
            mSocket.Connect(mdpEP);

            sendBuffer = Encoding.ASCII.GetBytes(service);
            mSocket.Send(sendBuffer);
            //Console.WriteLine("getting service: " + service);
            //Console.WriteLine("");
            mSocket.Close();
            receiveMultiCast();

        }

        public void receiveMultiCast()
        {
            int check = 1;
            bool off = false;
            while (check > 0)
            {
                int bytesReceived = mdcSocket.ReceiveFrom(receiveBuffer, ref endPoint);
                check = bytesReceived;
                IPEndPoint mdpEndPoint = (IPEndPoint)endPoint;
                int index = 0;
                string mktPrice = Encoding.ASCII.GetString(receiveBuffer, index, bytesReceived);

                if (mktPrice.Contains("~"))
                {
                    check = mktPrice.Length - 5;
                    off = true;
                }
                else
                    check = mktPrice.Length - 4;

                if (mktPrice.Contains("<?xml"))
                {
                    mktPrice = mktPrice.Remove(mktPrice.Length - 1);
                    displayXML(mktPrice);
                }
                else //when not xml
                {
                    mktPrice = mktPrice.Remove(check);
                    ServiceOrder s = ConstructOrder(mktPrice);
                    Order o = (Order)s;
                    //Console.WriteLine(o.ToString());
                    if (o.ToString().Contains(Form1.traderID))
                        position.Add(o.ToString());
                    if (o.ToString().Contains(" B "))
                        bids.Add(o.ToString());
                    if (o.ToString().Contains(" S "))
                        offers.Add(o.ToString());

                    if (off)
                        check = 0;
                }

            }


            //This is how you extract the strings to put in GUI
           // Console.WriteLine("Bids");
            //have to reverse the order so its highest price first
            bids.Reverse();
            //foreach (string s in bids)
            //    Console.WriteLine(s);

            ////Console.WriteLine();

            ////Offers already in correct order
            //Console.WriteLine("Offers");
            //foreach (string s in offers)
            //    Console.WriteLine(s);

            //Console.WriteLine();

            ////the traders current position
            //Console.WriteLine("Current Position");
            //foreach (string trade in position)
            //    Console.WriteLine(trade);


            //start a new thread for this
            offers.Clear();
            bids.Clear();
            Thread input = new Thread(getInput);
            input.Start();
        }


        private ServiceOrder BuildOrder(string[] mktOrder)
        {
            string id = mktOrder[0];
            string inst = mktOrder[1];
            string type = mktOrder[2];
            string bs = mktOrder[3];
            int quant = Int32.Parse(mktOrder[4]);
            double price = Double.Parse(mktOrder[5]);

            ServiceOrder serv = new ServiceOrder(id, inst, type, bs, price, quant);
            return serv;
        }

        private ServiceOrder ConstructOrder(string mktOrder)
        {
            string[] orderString = new string[6];
            int mark = 0;
            string part = "";
            for (int i = 0; i < mktOrder.Length; i++)
            {

                if (!mktOrder.ElementAt(i).Equals('|'))
                {
                    part += mktOrder.ElementAt(i);
                }
                else
                {
                    orderString[mark] = part;
                    mark++;
                    part = "";
                }

            }

            orderString[mark] = part;
            ServiceOrder serv = BuildOrder(orderString);
            return serv;
        }

        public void Start()
        {
            //Console.WriteLine("Market-Data Consumer Service Started - (Using MultiCast)");
            byte[] receiveBuffer = new byte[512];
            entry = Dns.GetHostByName(Dns.GetHostName());
            localEP = new IPEndPoint(entry.AddressList[0], 30002);

            //test code to change up what services we are generating
            //Console.WriteLine("Please enter the service you wish to see");
            //Console.WriteLine("Available Services are:");
            //for (int i = 0; i < currentTickers.Length; i++)
            //    Console.WriteLine(currentTickers[i]);

            endPoint = new IPEndPoint(IPAddress.Any, 0);
            mdcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            mdcSocket.Bind(localEP);
            mdcSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);

            getInput();

        }

        private string EnterOrder()
        {
            string ret;
            //Console.WriteLine("Trader ID is: " + Id);
            order = Form1.traderID;
            //Console.Write("Enter Service: ");
            ret = Form2.ins;
            order += "|" + ret + "|" + "Market" + "|";

            string bs = null;
            if (Form2.button1Clicked)
            {
                bs = "B";
            }
            if (Form2.button2Clicked)
            {
                bs = "S";
            }

            order += bs + "|";
            //Console.Write("How many contracts? ");
            order += Form2.quantity + "|";
            //Console.Write("At what price? ");
            order += Form2.price;
            order += "ORDR";
            sendBuffer = Encoding.ASCII.GetBytes(order);
            return ret;
        }

        public void getInput()
        {
            if (login == false)
            {
                TraderLogin();
                login = true;
            }
            bool check = false;
            bool send = false;
            //Console.WriteLine("To enter an order type ORDR");
            //Console.Write("Enter Symbol:  ");
            serv = Form2.orderType;
            if (serv.Length > 4)
                serv = serv.Substring(0, 4);
            serv = serv.ToUpper();
            while (serv != null)
            {
                if (serv.Equals(Form2.orderType))
                {
                    serv = EnterOrder();
                    send = true;
                }


                 if (serv.Equals(Form2.ins))
                {
                    check = true;
                    break;
                }

                if (check)
                    break;
                //if (check == false)
                //{
                //    Console.WriteLine("You entered an invalid symbol!  Please re-enter symbol");
                //    serv = (string)Console.ReadLine();
                //    serv = serv.ToUpper();
                //}
            }
            if (check && send)
                SendOrder();

            else if (check)
                getQuotes(serv);

            check = false;
            send = false;
        }

        public static void DisableMulticastLoopBack(Socket sockInstance)
        {
            sockInstance.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, 0);
        }

        private static void createXSLT()
        {
            string xsltMsg = "<?xml version = \"1.0\" encoding=\"ISO-8859-1\" ?>";

            xsltMsg += "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">";
            xsltMsg += "<xsl:output method=\"html\" />";
            xsltMsg += "<xsl:template match=\"/\">";
            xsltMsg += "<html><body><h2>Trade Printout</h2>";
            xsltMsg += "<table border=\"1\"><tr align=\"center\"><th>Service</th><th bgcolor=\"red\" width=\"50 px\">Bid ID</th><th bgcolor=\"green\" width=\"50 px\">Offer ID</th><th>Quantity</th><th>Price</th></tr>";
            xsltMsg += "<xsl:for-each select=\"TQ/Trade\">";
            xsltMsg += "<tr align=\"center\"><td><xsl:value-of select=\"Serv\"/></td><td bgcolor=\"red\"><xsl:value-of select=\"bID\"/></td><td bgcolor=\"green\"><xsl:value-of select=\"sID\"/></td><td><xsl:value-of select=\"quant\"/></td><td><xsl:value-of select=\"pr\"/></td></tr>";
            xsltMsg += "</xsl:for-each></table></body></html></xsl:template></xsl:stylesheet>";

            System.IO.File.WriteAllText(@"C:\\Temp\\A1Exchange.xslt", xsltMsg);
        }

        private static void displayXML(string xmlMsg)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlMsg);

            doc.Save("C:\\Temp\\A1Exchange.xml");

            XslTransform tranXml = new XslTransform();
            tranXml.Load("C:\\Temp\\A1Exchange.xslt");

            tranXml.Transform("C:\\Temp\\A1Exchange.xml", "C:\\Temp\\A1Exchange.html");
            Process.Start("C:\\Temp\\A1Exchange.html");
        }
    }
}